package com.wang.tool.okhttp;


import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 模拟实现python的生成器
 *
 * @author shaopeng
 * @date 2024/2/26
 */
public class SimpleGenerator<T> {

    private volatile LinkedBlockingQueue<T> queue = new LinkedBlockingQueue<>();
    private final long beginTime = System.currentTimeMillis();
    //    默认超时5分钟
    private int timeout = 300000;
    private volatile boolean end = false;
    private volatile Throwable error;
    //    是否被消费过
    private volatile boolean consume = false;

    /**
     * 推送信息
     *
     * @param data
     */
    public void push(T data) {
        try {
            queue.put(data);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(e);
        }
    }

    /**
     * 标记已结束
     */
    public void markEnd() {
        this.end = true;
    }

    /**
     * 标记失败
     *
     * @param e
     */
    public void markError(Throwable e) {
        this.error = e;
        this.end = true;
    }

    /**
     * 不可多次调用
     *
     * @return
     */
    public synchronized Iterator<T> iterator() {
        if (consume) {
            throw new IllegalArgumentException("iterator is already consume");
        }
        consume = true;
        return new Iterator<T>() {

            private T nextItem;

            private Boolean hasNext;

            @Override
            public boolean hasNext() {
//            异常记录
                if (error != null) {
                    throw new RuntimeException(error);
                }
//            还未消费
                if (hasNext != null) {
                    return true;
                }
//            虽然标记结束，但是还未消费完全
                if (end && queue.isEmpty()) {
                    return false;
                }

                try {
//                还未结束，等数据
                    while (!end && queue.isEmpty()) {
                        if (System.currentTimeMillis() - beginTime >= timeout) {
                            throw new RuntimeException("generator is timeout");
                        }
                        Thread.sleep(100);
                    }
                    nextItem = queue.poll();
                    hasNext = true;
                    return true;
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException(e);
                }
            }

            @Override
            public T next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                T item = nextItem;
                hasNext = null;
                nextItem = null;
                return item;
            }
        };
    }


    /**
     * 获取最后的数据
     *
     * @return
     */
    public T fetchLastData() {
        Iterator<T> iterator = iterator();
        T ret = null;
        while (iterator.hasNext()) {
            T data = iterator.next();
            if (data != null) {
                ret = data;
            }
        }
        return ret;
    }

    public boolean isEnd() {
        return end;
    }

    public Throwable getError() {
        return error;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public long getBeginTime() {
        return beginTime;
    }
}
